package org.dromara.solonplugins.jasypt;

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.noear.solon.Utils;
import org.noear.solon.core.AopContext;
import org.noear.solon.core.Props;

public final class JasyptManager {

	private final static String ENCRYPT_PREFIX = "ENC(";
	private final static String ENCRYPT_SUFFIX = ")";
	private final static String PRE = "jasypt.encryptor.";
	private final static String PASSWORD = PRE + "password";// 加密的密码
	private final static String ALGORITHM = PRE + "algorithm";// 加密的算法
	private final static String POOL_SIZE = PRE + "pool-size";// 缓冲池大小
	
	private JasyptManager() {}
	
	public static void init(AopContext context) {
		Props props = context.cfg();
		StringEncryptor stringEncryptor = createPBEDefault(props);

		props.forEach((k, v) -> {
			if (!PASSWORD.equals(k.toString())
					&& !ALGORITHM.equals(k.toString())
					&& !POOL_SIZE.equals(k.toString())
					&& isEncrypted(v)) {
				String val = unwrapEncryptedValue(v);
				try {
					props.put(k, stringEncryptor.decrypt(val));
				} catch (Exception e1) {
					throw new DecryptionException("The key:" + k + " decrypt failed", e1);
				}
			}
		});
	}
	
	
	/**
	 * 是否是加密串
	 */
	private static boolean isEncrypted(Object value) {
		if (value == null) {
			return false;
		}
		String property = value.toString();
		final String trimmedValue = property.trim();
		return (trimmedValue.startsWith(ENCRYPT_PREFIX) && trimmedValue.endsWith(ENCRYPT_SUFFIX));
	}

	/**
	 * 获取加密串内容
	 */
	private static String unwrapEncryptedValue(Object value) {
		String property = value.toString();
		return property.substring(ENCRYPT_PREFIX.length(), (property.length() - ENCRYPT_SUFFIX.length()));
	}

	/**
	 * 加解密算法
	 */
	private static StringEncryptor createPBEDefault(final Props props) {
		PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
		SimpleStringPBEConfig config = new SimpleStringPBEConfig();
		config.setPassword(getRequired(props, PASSWORD));
		config.setAlgorithm(props.get(ALGORITHM, "PBEWITHHMACSHA512ANDAES_256"));
		config.setKeyObtentionIterations(1000);
		config.setPoolSize(props.get(POOL_SIZE, "1"));
		config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
		config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
		config.setStringOutputType("base64");
		encryptor.setConfig(config);
		return encryptor;
	}

	/**
	 * 获取必填值，没有则抛异常
	 */
	private static String getRequired(Props props, String key) {
		String value = props.get(key);
		if (Utils.isBlank(value)) {
			throw new IllegalStateException(
					String.format("Required Encryption configuration property missing: %s", key));
		}
		return value;
	}
}
